using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using IGGCore;
using System.Globalization;
using System.IO;

namespace IGGConsole
{
    /// <summary>
    /// The manager of the command line side of the application
    /// Information requests are sent to the main channel via events
    /// </summary>
    public class ConsoleManager
    {
        private int ACTIVE_DELAY_MINUTES = 1;
        private int INACTIVE_DELAY_MINUTES = 15;

        private BoxesManager m_boxesManager;
        private bool m_updated = false;
        private bool m_consoleInitialized = false;
        private int m_homePageLoadedItems = 0;
        private int m_homePageMaxItems = 3;
        private MainChannel m_mainChannel = null;
        private DateTime m_lastRefresh;
        private DateTime m_currentDate = DateTime.Now;
        private bool m_statsLoaded = false;
        private bool m_needBoxes = true;

        private Thread m_twitterThread;
        private bool m_twitterThreadActive = false;

        /// <summary>
        /// Main constructor
        /// </summary>
        public ConsoleManager()
        {
            m_boxesManager = new BoxesManager();
            m_mainChannel = new MainChannel();

            FileStream filestream = new FileStream("D:\\out.txt", FileMode.Create);
            StreamWriter streamwriter = new StreamWriter(filestream);
            streamwriter.AutoFlush = true;
            Console.SetOut(streamwriter);
            Console.SetError(streamwriter);

            Console.OutputEncoding = Encoding.GetEncoding(TxtConstants.COMMANDLINE_ENCODING);
            Console.SetWindowSize(80, TxtConstants.COMMANDLINE_HEIGHT);

            //Console.WriteLine("Welcome to IGG Console.");
            //Console.WriteLine();

            if (ToolBox.YesterdayScores())
            {
                m_currentDate = DateTime.Now.AddDays(-1);
            }
        }

        /// <summary>
        /// Manage the refreshed event from the main channel
        /// </summary>
        private void m_mainChannel_ScoreboardRefreshed(object sender, EventArgs e)
        {
            m_updated = true;
            m_lastRefresh = DateTime.Now;
            if (m_consoleInitialized == false)
            {
                InitializeGameView();
                m_consoleInitialized = true;
            }
        }

        /// <summary>
        /// Start the console application
        /// </summary>
        public void StartConsoleApplication()
        {
            Console.WriteLine();
            Console.Write(" Loading the main scoreboard...");
            try
            {
                m_updated = ReloadScoreboard(null);
                if (m_mainChannel.ScoreBoard.GamesList.Games.Count > 0)
                {
                    m_mainChannel.UpdateBoxscore(m_currentDate);
                    m_mainChannel.UpdateNews(false);
                }
                m_mainChannel.ScoreBoardDated = m_mainChannel.ScoreBoard;
                m_lastRefresh = DateTime.Now;
                if (m_consoleInitialized == false)
                {
                    InitializeGameView();
                    m_consoleInitialized = true;
                }
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(ex.Message);
                Console.WriteLine();
                Console.ForegroundColor = ConsoleColor.Gray;

                Console.WriteLine();
                Console.WriteLine("Unable to start the baseball console app. Press Key.");
                Console.WriteLine(ex.StackTrace);
                Console.Read();
            }
        }

        /// <summary>
        /// Reload the scoreboard as many times as necessary
        /// </summary>
        public bool ReloadScoreboard(string selectedId)
        {
            int maxTries = 8;
            int currentTry = 1;
            int currentDelay = 1000;
            bool success = false;
            while (success == false && currentTry <= maxTries)
            {
                try
                {
                    m_mainChannel.RefreshScoreboard(m_currentDate, selectedId);
                    success = true;
                }
                catch
                {
                    Thread.Sleep(currentDelay);
                    currentDelay = currentDelay * 2;
                }
                finally
                {
                    currentTry++;
                }
            }
            return success;
        }

        /// <summary>
        /// Initialize the command line game view
        /// </summary>
        public void InitializeGameView()
        {
            ConsoleKeyInfo info;
            ConsoleKey key = 0;
            if (m_mainChannel.ScoreBoard.GamesList.Games.Count == 0)
            {
                StartHomeThreads();
            }
            m_boxesManager.InitializeBoxedGames(m_mainChannel.ScoreBoard);
            m_mainChannel.UpdateTweets();
            m_mainChannel.UpdateAllBoxscores(m_currentDate, m_mainChannel.ScoreBoard);
            ShowGameView();

            do
            {
                if (Console.KeyAvailable)
                {
                    info = Console.ReadKey(true); 
                    key = info.Key;
                    if (ToolBox.CheckArrowKey(info))
                    {
                        m_needBoxes = true;
                        m_boxesManager.ManageSelectionNavigator(m_mainChannel.ScoreBoard, info.Key);
                        Modes.ManageArrowChange();
                        m_mainChannel.UpdateBoxscore(m_currentDate);
                        ShowGameView();
                    }
                    else
                    {
                        if (info.Key != ConsoleKey.W)
                        {
                            m_twitterThreadActive = false;
                        }
                        if (info.Key == ConsoleKey.F5)
                        {
                            //m_updated = ReloadScoreboard(m_mainChannel.ScoreBoard.SelectedGame.Id);
                            //m_mainChannel.UpdateBoxscore(m_currentDate);
                            m_mainChannel.UpdateTweets();
                            m_mainChannel.UpdateAllBoxscores(m_currentDate, m_mainChannel.ScoreBoard);
                            m_lastRefresh = DateTime.Now;
                        }
                        else if (info.Key == ConsoleKey.F2)
                        {
                            // GO BACK A DAY
                            m_currentDate = m_currentDate.AddDays(-1);
                            m_updated = ReloadScoreboard(null);
                            m_mainChannel.UpdateBoxscore(m_currentDate);
                            m_lastRefresh = DateTime.Now;
                        }
                        else if (info.Key == ConsoleKey.F3)
                        {
                            // A DAY LATER
                            m_currentDate = m_currentDate.AddDays(1);
                            m_updated = ReloadScoreboard(null);
                            m_mainChannel.UpdateBoxscore(m_currentDate);
                            m_lastRefresh = DateTime.Now;
                        }
                        else if (info.Key == ConsoleKey.M)
                        {
                            // DO NOTHING
                        }
                        else if (Modes.GetMode(info.Key) != null)
                        {
                            Modes.CurrentMode = Modes.GetMode(info.Key);
                            UpdateModeData(Modes.CurrentMode.AssociatedKey);
                            ShowGameView();
                            if (m_mainChannel.ScoreBoard.ActiveTeam != null)
                            {
                                Modes.CurrentMode = Modes.GetMode(ConsoleKey.M);
                                UpdateModeData(Modes.CurrentMode.AssociatedKey);
                                ShowGameView();
                                m_mainChannel.ScoreBoard.ActiveTeam = null;
                            }
                        }
                    }
                }
                if (m_updated && m_mainChannel.ScoreBoard.GamesList.Games.Count > 0)
                {
                    m_updated = false;
                    if (m_needBoxes)
                    {
                        m_boxesManager.InitializeBoxedGames(m_mainChannel.ScoreBoard);
                    }
                    ShowGameView();
                }
                Thread.Sleep(100);
                TimeSpan currentDelay = DateTime.Now - m_lastRefresh;
                int delay = ACTIVE_DELAY_MINUTES;
                if (m_mainChannel.ScoreBoard.SelectedGame!=null 
                    && m_mainChannel.ScoreBoard.SelectedGame.Status.Indicator.Category != Indicator.IndicatorCategoy.IN_PROGRESS)
                {
                    delay = INACTIVE_DELAY_MINUTES;
                }
                else if (Modes.CurrentMode.AssociatedKey != ConsoleKey.G)
                {
                    delay = INACTIVE_DELAY_MINUTES;
                }
                if (currentDelay.TotalMinutes >= delay)
                {
                    if (m_mainChannel.ScoreBoard.SelectedGame != null)
                    {
                        m_updated = ReloadScoreboard(m_mainChannel.ScoreBoard.SelectedGame.Id);
                        m_mainChannel.UpdateBoxscore(m_currentDate);
                        m_lastRefresh = DateTime.Now;
                    }
                }

            } while (key != ConsoleKey.Escape);
        }

        /// <summary>
        /// Triggers a data update
        /// </summary>
        /// <param name="key"></param>
        private void UpdateModeData(ConsoleKey key)
        {
            m_needBoxes = true;
            if (key == ConsoleKey.D1 || key == ConsoleKey.D2 || key == ConsoleKey.D3 ||
                key == ConsoleKey.D4 || key == ConsoleKey.D5 || key == ConsoleKey.D6 ||
                key == ConsoleKey.D7 || key == ConsoleKey.D8 || key == ConsoleKey.D9 || key == ConsoleKey.D0)
            {
                if (m_statsLoaded == false)
                {
                    m_mainChannel.UpdateStatistics();
                    m_statsLoaded = true;
                }
            }
            else if (key == ConsoleKey.S || key == ConsoleKey.A)
            {
                m_mainChannel.UpdateStandings();
            }
            else if (key == ConsoleKey.H)
            {
                m_mainChannel.UpdateHistory();
            }
            else if (key == ConsoleKey.L || key == ConsoleKey.D)
            {
                m_mainChannel.UpdateTeamAlignment(m_currentDate);
            }
            else if (key == ConsoleKey.B)
            {
                m_mainChannel.UpdateBoxscore(m_currentDate);
            }
            else if (key == ConsoleKey.N)
            {
                m_mainChannel.UpdateNews(false);
            }
            else if (key == ConsoleKey.M)
            {
                m_mainChannel.UpdateTeam();
            }
            else if (key == ConsoleKey.J)
            {
                m_mainChannel.UpdateInjuries();
            }
            else if (key == ConsoleKey.F)
            {
                m_mainChannel.UpdateBaseballReference();
            }
            else if (key == ConsoleKey.R)
            {
                m_mainChannel.UpdateTransactions();
            }
            else if (key == ConsoleKey.Z)
            {
                StartHomeThreads();
            }
            else if (key == ConsoleKey.W)
            {
                m_twitterThreadActive = true;
                m_twitterThread = new Thread(new ThreadStart(RunTwitterThread));
                m_twitterThread.Start();
            }
            else if (key == ConsoleKey.O)
            {
                //m_needBoxes = false;
                m_mainChannel.UpdateTweets();
                m_mainChannel.UpdateAllBoxscores(m_currentDate, m_mainChannel.ScoreBoard);
                m_mainChannel.UpdateNews(false);
            }
        }

        private void RunTwitterThread()
        {
            while (m_twitterThreadActive)
            {
                Console.Clear();
                Console.WriteLine("");
                Console.WriteLine(" Loading Tweets...");
                Console.WriteLine("");
                Console.WriteLine(" Please wait.");
                Console.Clear();
                m_mainChannel.UpdateTweets();
                for (int i = 0; i < 12; i++)
                {
                    Console.WriteLine();
                    Console.WriteLine(" " + m_mainChannel.ScoreBoard.Tweets[i].Author.ToUpper());
                    StringFormatter.FormatLongText(m_mainChannel.ScoreBoard.Tweets[i].Text);
                }
                Thread.Sleep(120000);
            }
        }


        private void StartHomeThreads()
        {
            m_homePageLoadedItems = 0;
            Thread m_newsThread = new Thread(new ThreadStart(LoadThreadedNews));
            m_newsThread.Start();
            Thread m_twitThread = new Thread(new ThreadStart(LoadThreadedTwitter));
            m_twitThread.Start();
            Thread m_transThread = new Thread(new ThreadStart(LoadThreadedTransactions));
            m_transThread.Start();
        }

        private void LoadThreadedNews()
        {
            Console.WriteLine();
            m_mainChannel.UpdateNews(false);
            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine();
                Console.WriteLine(" " + m_mainChannel.ScoreBoard.News[i].Title.ToUpper());
                StringFormatter.FormatLongText(m_mainChannel.ScoreBoard.News[i].Content);
            }
            CheckAllItemLoaded();
        }

        private void LoadThreadedTwitter()
        {
            m_mainChannel.UpdateTweets();
            for (int i = 0; i < 3; i++)
            {
                Console.WriteLine();
                Console.WriteLine(" " + m_mainChannel.ScoreBoard.Tweets[i].Author.ToUpper());
                StringFormatter.FormatLongText(m_mainChannel.ScoreBoard.Tweets[i].Text);
            }
            CheckAllItemLoaded();
        }

        private void LoadThreadedTransactions()
        {
            m_mainChannel.UpdateTransactions();
            new ModeTransactionsFormatter().FormatMode(m_mainChannel.ScoreBoard, 3);
            CheckAllItemLoaded();
        }

        /// <summary>
        /// Check if all the items loaded by threads in the home page are loaded.
        /// Then put the cursor at top left corner
        /// </summary>
        private void CheckAllItemLoaded()
        {
            m_homePageLoadedItems++;
            if (m_homePageLoadedItems == m_homePageMaxItems)
            {
                m_mainChannel.UpdateBaseballReference();
                Console.WriteLine();
                Console.WriteLine();
                Console.WriteLine(" " + m_mainChannel.GetBaseballReferenceTidbit());
                Console.CursorTop = 0;
                Console.CursorLeft = 0;
            }
        }

        /// <summary>
        /// Show the command line game view
        /// </summary>
        /// <param name="scoreboard"></param>
        private void ShowGameView()
        {
            if (Modes.CurrentMode.AssociatedKey != ConsoleKey.W)
            {
                //Console.Clear();
                string title = "MLB Scoreboard for " + ToolBox.GetFormattedDate(m_mainChannel.ScoreBoard.Date)
                    + " (updt @ " + m_mainChannel.ScoreBoard.LastUpdate.ToString("h:mm:ss") + ")";
                Console.Title = title;
                if (m_needBoxes && m_mainChannel.ScoreBoard.GamesList.Games.Count > 0)
                {
                    m_boxesManager.BuildBoxes(m_mainChannel.ScoreBoard);
                    Console.WriteLine();
                }
                Modes.CurrentMode.ModeFormatter.FormatMode(m_mainChannel.ScoreBoard);
            }
        }
    }
}
